// base objects extensions
// this code is heavily minified and it couldn not be changed frequently
;(function(){

var O = Object, A = Array, Ap = A.prototype, S = String, Sp = S.prototype, Fp = Function.prototype, D = Date, M = Math

function add (d, s) { if (d) for (var k in s) if (!(k in d)) d[k] = s[k]; return d }
function extend (d, s) { if (d) for (var k in s) d[k] = s[k]; return d }

add
(
	O,
	{
		add: add,
		extend: extend,
		copy: function (s) { var d = {}; for (var k in s) d[k] = s[k]; return d },
		keys: function (s) { var r = []; for (var k in s) r.push(k); return r },
		keysCount: function (s) { var l = 0; for (var k in s) l++; return l },
		values: function (s) { var r = []; for (var k in s) r.push(s[k]); return r },
		isEmpty: function (s) { for (var k in s) return false; return true }
	}
)

add
(
	S,
	{
		localeCompare: function (a, b) { return a < b ? -1 : (a > b ? 1 : 0) }
	}
)

add
(
	Sp,
	{
		trim: function () { return this.replace(/^\s+|\s+$/g, '') },
		capitalize: function () { return this.charAt(0).toUpperCase() + this.substr(1) }
	}
)

add
(
	Fp,
	{
		mixIn: function (module) { return extend(this.prototype, module.prototype) },
		extend: function (s) { for (var k in s) this[k] = s[k]; return this },
		bind: function (inv, args) { var me = this; return function () { me.apply(inv, args || arguments) } }
	}
)

var ceil = M.ceil, floor = M.floor, round = M.round, random = M.random
add(M, {longRandom: function () { return (new D()).getTime().toString() + round(random() * 1E+17) }})


add
(
	Ap,
	{
		indexOf: function (v, i)
		{
			var len = this.length
			
			if ((i = +i))
			{
				if (i < 0)
					i = ceil(i) + len
				else
					i = floor(i)
			}
			else
				i = 0
			
			for (; i < len; i++)
				if (i in this && this[i] === v)
					return i
			return -1
		},
		uniq: function ()
		{
			var res = [], j = 0
			for (var i = 0, il = this.length; i < il; i++)
			{
				var v = this[i]
				if (res.indexOf(v) === -1)
					res[j++] = v
			}
			return res
		},
		forEach: function (f, inv) { for (var i = 0, len = this.length; i < len; i++) f.call(inv, this[i], i, this) },
		map: function(f, inv)
		{
			var len = this.length,
				res = new A(len)
			for (var i = 0; i < len; i++)
				if (i in this)
					res[i] = f.call(inv, this[i], i, this)
			return res
		}
	}
)

add(A, {copy: function (src) { return Ap.slice.call(src) }})

})();
;(function(){

var s = self

if (!s.log)
{
	// Firebug
	if (s.console && s.console.firebug)
		s.log = console.log
	
	// Opera
	else if (s.opera && s.opera.postError)
		s.log = function () { return s.opera.postError(arguments) }
	
	// other consoles
	else if (s.console && s.console.log)
		s.log = function () { return s.console.log(Array.prototype.slice.call(arguments).join(', ')) }
	
	// none
	else
		s.log = function () {}
}

})();

// 1, 2, 5: банкир, банкира, банкиров
String.prototype.plural = Number.prototype.plural = function (a, b, c)
{
	if (this % 1)
		return b
	
	var v = Math.abs(this) % 100
	if (11 <= v && v <= 19)
		return c
	
	v = v % 10
	if (2 <= v && v <= 4)
		return b
	if (v == 1)
		return a
	
	return c
}

;(function(){

var random = Math.random

Array.prototype.randomize = function ()
{
	for (var i = 0, il = this.length; i < il; i++)
	{
		var j = (random() * il) >> 0
		var v = this[j]
		this[j] = this[i]
		this[i] = v
	}
	
	return this
}

Array.prototype.random = function (n)
{
	var len = this.length
	
	if (n > len)
		n = len
	
	if (n > 1)
	{
		var copy = this.slice()
		copy.randomize()
		return n === len ? copy : copy.slice(0, n)
	}
	
	if (n === 1)
		return [this[(random() * len) >> 0]]
	
	// n <= 0
	return []
}

})();
;(function(){

var myName = 'MVC'

function Me () {}

Me.prototype =
{
	__mvc_interlink: function ()
	{
		var constructor = this.constructor,
			model = this.model = new constructor.Model(),
			view = this.view = new constructor.View(),
			controller = this.controller = new constructor.Controller()
		
		model.view = controller.view = view
		view.controller = controller
		controller.model = model
		model.parent = view.parent = controller.parent = this
	},
	
	initialize: function () {}
}

self[myName] = Me
Me.className = myName

function Model () {}
Model.prototype.initialize = function () {}
Model.className = myName + '.Model'
Me.Model = Model

function View () {}
View.prototype.initialize = function () {}
View.className = myName + '.View'
Me.View = View

function Controller () {}
Controller.prototype.initialize = function () {}
Controller.className = myName + '.Controller'
Me.Controller = Controller


Me.setup = function (klass, name, parent)
{
	if (!parent)
		parent = Me
	
	klass.prototype = new parent()
	klass.className = name
	
	
	function Model ()
	{
		this.constructor = Model
		this.initialize.apply(this, arguments)
	}
	Model.className = name + '.Model'
	Model.prototype = new parent.Model()
	klass.Model = Model
	
	
	function View ()
	{
		this.constructor = View
		this.initialize.apply(this, arguments)
	}
	View.className = name + '.View'
	View.prototype = new parent.View()
	klass.View = View
	
	
	function Controller ()
	{
		this.constructor = Controller
		this.initialize.apply(this, arguments)
	}
	Controller.className = name + '.Controller'
	Controller.prototype = new parent.Controller()
	klass.Controller = Controller
	
	
	return klass
}

Me.create = function (name, parent)
{
	function klass ()
	{
		this.constructor = klass
		this.__mvc_interlink()
		this.initialize()
	}
	
	return this.setup(klass, name, parent)
}

})();

function $ (id) { return document.getElementById(id) }

$.onload = function (fn) { return self.addEventListener('load', fn, false) }
$.include = function (src)
{
	var me = arguments.callee
	var cache = me.cache || (me.cache = {}) 
	if (me.cache[src])
		return me.cache[src]
	var node = document.createElement('script')
	node.type = 'text/javascript'
	node.src = src
	document.getElementsByTagName('head')[0].appendChild(node)
	cache[src] = node
	return node
}

// inspired by RequireJS (http://requirejs.org/) by James Burke (http://twitter.com/jrburke)
;(function(){

var myName = 'require',
	states = {}

function run (callbacks)
{
	for (var i = 0, il = callbacks.length; i < il; i++)
		setTimeout(callbacks[i], 0)
}

function Me (name, f)
{
	var src = Me.names[name] || name
	
	var state = states[src]
	
	if (state)
	{
		if (state.loaded)
			run([f])
		else
			state.callbacks.push(f)
	}
	else
	{
		state = states[src] = {callbacks: [f]}
		
		function onload ()
		{
			if (state.loaded)
				return
			state.loaded = true
			
			run(state.callbacks)
		}
		
		script = state.node = Me.rootNode.appendChild(document.createElement('script'))
		script.addEventListener('load', onload, false)
		script.src = src
	}
	
	return state.node
}

Me.names = {}
Me.rootNode = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.documentElement

Me.className = myName
self[myName] = Me

})();
/*
 * Sizzle CSS Selector Engine - v1.0
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
;(function(){var q=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,i=0,d=Object.prototype.toString,o=false;var b=function(E,u,B,w){B=B||[];var e=u=u||document;if(u.nodeType!==1&&u.nodeType!==9){return[]}if(!E||typeof E!=="string"){return B}var C=[],D,z,H,G,A,t,s=true,x=p(u);q.lastIndex=0;while((D=q.exec(E))!==null){C.push(D[1]);if(D[2]){t=RegExp.rightContext;break}}if(C.length>1&&j.exec(E)){if(C.length===2&&f.relative[C[0]]){z=g(C[0]+C[1],u)}else{z=f.relative[C[0]]?[u]:b(C.shift(),u);while(C.length){E=C.shift();if(f.relative[E]){E+=C.shift()}z=g(E,z)}}}else{if(!w&&C.length>1&&u.nodeType===9&&!x&&f.match.ID.test(C[0])&&!f.match.ID.test(C[C.length-1])){var I=b.find(C.shift(),u,x);u=I.expr?b.filter(I.expr,I.set)[0]:I.set[0]}if(u){var I=w?{expr:C.pop(),set:a(w)}:b.find(C.pop(),C.length===1&&(C[0]==="~"||C[0]==="+")&&u.parentNode?u.parentNode:u,x);z=I.expr?b.filter(I.expr,I.set):I.set;if(C.length>0){H=a(z)}else{s=false}while(C.length){var v=C.pop(),y=v;if(!f.relative[v]){v=""}else{y=C.pop()}if(y==null){y=u}f.relative[v](H,y,x)}}else{H=C=[]}}if(!H){H=z}if(!H){throw"Syntax error, unrecognized expression: "+(v||E)}if(d.call(H)==="[object Array]"){if(!s){B.push.apply(B,H)}else{if(u&&u.nodeType===1){for(var F=0;H[F]!=null;F++){if(H[F]&&(H[F]===true||H[F].nodeType===1&&h(u,H[F]))){B.push(z[F])}}}else{for(var F=0;H[F]!=null;F++){if(H[F]&&H[F].nodeType===1){B.push(z[F])}}}}}else{a(H,B)}if(t){b(t,e,B,w);b.uniqueSort(B)}return B};b.uniqueSort=function(s){if(c){o=false;s.sort(c);if(o){for(var e=1;e<s.length;e++){if(s[e]===s[e-1]){s.splice(e--,1)}}}}};b.matches=function(e,s){return b(e,null,null,s)};b.find=function(y,e,z){var x,v;if(!y){return[]}for(var u=0,t=f.order.length;u<t;u++){var w=f.order[u],v;if((v=f.match[w].exec(y))){var s=RegExp.leftContext;if(s.substr(s.length-1)!=="\\"){v[1]=(v[1]||"").replace(/\\/g,"");x=f.find[w](v,e,z);if(x!=null){y=y.replace(f.match[w],"");break}}}}if(!x){x=e.getElementsByTagName("*")}return{set:x,expr:y}};b.filter=function(B,A,E,u){var t=B,G=[],y=A,w,e,x=A&&A[0]&&p(A[0]);while(B&&A.length){for(var z in f.filter){if((w=f.match[z].exec(B))!=null){var s=f.filter[z],F,D;e=false;if(y==G){G=[]}if(f.preFilter[z]){w=f.preFilter[z](w,y,E,G,u,x);if(!w){e=F=true}else{if(w===true){continue}}}if(w){for(var v=0;(D=y[v])!=null;v++){if(D){F=s(D,w,v,y);var C=u^!!F;if(E&&F!=null){if(C){e=true}else{y[v]=false}}else{if(C){G.push(D);e=true}}}}}if(F!==undefined){if(!E){y=G}B=B.replace(f.match[z],"");if(!e){return[]}break}}}if(B==t){if(e==null){throw"Syntax error, unrecognized expression: "+B}else{break}}t=B}return y};var f=b.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")}},relative:{"+":function(y,e,x){var v=typeof e==="string",z=v&&!/\W/.test(e),w=v&&!z;if(z&&!x){e=e.toUpperCase()}for(var u=0,t=y.length,s;u<t;u++){if((s=y[u])){while((s=s.previousSibling)&&s.nodeType!==1){}y[u]=w||s&&s.nodeName===e?s||false:s===e}}if(w){b.filter(e,y,true)}},">":function(x,s,y){var v=typeof s==="string";if(v&&!/\W/.test(s)){s=y?s:s.toUpperCase();for(var t=0,e=x.length;t<e;t++){var w=x[t];if(w){var u=w.parentNode;x[t]=u.nodeName===s?u:false}}}else{for(var t=0,e=x.length;t<e;t++){var w=x[t];if(w){x[t]=v?w.parentNode:w.parentNode===s}}if(v){b.filter(s,x,true)}}},"":function(u,s,w){var t=i++,e=r;if(!s.match(/\W/)){var v=s=w?s:s.toUpperCase();e=n}e("parentNode",s,t,u,v,w)},"~":function(u,s,w){var t=i++,e=r;if(typeof s==="string"&&!s.match(/\W/)){var v=s=w?s:s.toUpperCase();e=n}e("previousSibling",s,t,u,v,w)}},find:{ID:function(s,t,u){if(typeof t.getElementById!=="undefined"&&!u){var e=t.getElementById(s[1]);return e?[e]:[]}},NAME:function(t,w,x){if(typeof w.getElementsByName!=="undefined"){var s=[],v=w.getElementsByName(t[1]);for(var u=0,e=v.length;u<e;u++){if(v[u].getAttribute("name")===t[1]){s.push(v[u])}}return s.length===0?null:s}},TAG:function(e,s){return s.getElementsByTagName(e[1])}},preFilter:{CLASS:function(u,s,t,e,x,y){u=" "+u[1].replace(/\\/g,"")+" ";if(y){return u}for(var v=0,w;(w=s[v])!=null;v++){if(w){if(x^(w.className&&(" "+w.className+" ").indexOf(u)>=0)){if(!t){e.push(w)}}else{if(t){s[v]=false}}}}return false},ID:function(e){return e[1].replace(/\\/g,"")},TAG:function(s,e){for(var t=0;e[t]===false;t++){}return e[t]&&p(e[t])?s[1]:s[1].toUpperCase()},CHILD:function(e){if(e[1]=="nth"){var s=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(e[2]=="even"&&"2n"||e[2]=="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(s[1]+(s[2]||1))-0;e[3]=s[3]-0}e[0]=i++;return e},ATTR:function(v,s,t,e,w,x){var u=v[1].replace(/\\/g,"");if(!x&&f.attrMap[u]){v[1]=f.attrMap[u]}if(v[2]==="~="){v[4]=" "+v[4]+" "}return v},PSEUDO:function(v,s,t,e,w){if(v[1]==="not"){if(v[3].match(q).length>1||/^\w/.test(v[3])){v[3]=b(v[3],null,null,s)}else{var u=b.filter(v[3],s,t,true^w);if(!t){e.push.apply(e,u)}return false}}else{if(f.match.POS.test(v[0])||f.match.CHILD.test(v[0])){return true}}return v},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){e.parentNode.selectedIndex;return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(t,s,e){return !!b(e[3],t).length},header:function(e){return/h\d/i.test(e.nodeName)},text:function(e){return"text"===e.type},radio:function(e){return"radio"===e.type},checkbox:function(e){return"checkbox"===e.type},file:function(e){return"file"===e.type},password:function(e){return"password"===e.type},submit:function(e){return"submit"===e.type},image:function(e){return"image"===e.type},reset:function(e){return"reset"===e.type},button:function(e){return"button"===e.type||e.nodeName.toUpperCase()==="BUTTON"},input:function(e){return/input|select|textarea|button/i.test(e.nodeName)}},setFilters:{first:function(s,e){return e===0},last:function(t,s,e,u){return s===u.length-1},even:function(s,e){return e%2===0},odd:function(s,e){return e%2===1},lt:function(t,s,e){return s<e[3]-0},gt:function(t,s,e){return s>e[3]-0},nth:function(t,s,e){return e[3]-0==s},eq:function(t,s,e){return e[3]-0==s}},filter:{PSEUDO:function(w,s,t,x){var e=s[1],u=f.filters[e];if(u){return u(w,t,s,x)}else{if(e==="contains"){return(w.textContent||w.innerText||"").indexOf(s[3])>=0}else{if(e==="not"){var v=s[3];for(t=0,l=v.length;t<l;t++){if(v[t]===w){return false}}return true}}}},CHILD:function(e,u){var x=u[1],s=e;switch(x){case"only":case"first":while((s=s.previousSibling)){if(s.nodeType===1){return false}}if(x=="first"){return true}s=e;case"last":while((s=s.nextSibling)){if(s.nodeType===1){return false}}return true;case"nth":var t=u[2],A=u[3];if(t==1&&A==0){return true}var w=u[0],z=e.parentNode;if(z&&(z.sizcache!==w||!e.nodeIndex)){var v=0;for(s=z.firstChild;s;s=s.nextSibling){if(s.nodeType===1){s.nodeIndex=++v}}z.sizcache=w}var y=e.nodeIndex-A;if(t==0){return y==0}else{return(y%t==0&&y/t>=0)}}},ID:function(s,e){return s.nodeType===1&&s.getAttribute("id")===e},TAG:function(s,e){return(e==="*"&&s.nodeType===1)||s.nodeName===e},CLASS:function(s,e){return(" "+(s.className||s.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(w,u){var t=u[1],e=f.attrHandle[t]?f.attrHandle[t](w):w[t]!=null?w[t]:w.getAttribute(t),x=e+"",v=u[2],s=u[4];return e==null?v==="!=":v==="="?x===s:v==="*="?x.indexOf(s)>=0:v==="~="?(" "+x+" ").indexOf(s)>=0:!s?x&&e!==false:v==="!="?x!=s:v==="^="?x.indexOf(s)===0:v==="$="?x.substr(x.length-s.length)===s:v==="|="?x===s||x.substr(0,s.length+1)===s+"-":false},POS:function(v,s,t,w){var e=s[2],u=f.setFilters[e];if(u){return u(v,t,s,w)}}}};var j=f.match.POS;for(var m in f.match){f.match[m]=new RegExp(f.match[m].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var a=function(s,e){s=Array.prototype.slice.call(s);if(e){e.push.apply(e,s);return e}return s};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(k){a=function(v,u){var s=u||[];if(d.call(v)==="[object Array]"){Array.prototype.push.apply(s,v)}else{if(typeof v.length==="number"){for(var t=0,e=v.length;t<e;t++){s.push(v[t])}}else{for(var t=0;v[t];t++){s.push(v[t])}}}return s}}var c;if(document.documentElement.compareDocumentPosition){c=function(s,e){var t=s.compareDocumentPosition(e)&4?-1:s===e?0:1;if(t===0){o=true}return t}}else{if("sourceIndex" in document.documentElement){c=function(s,e){var t=s.sourceIndex-e.sourceIndex;if(t===0){o=true}return t}}else{if(document.createRange){c=function(u,s){var t=u.ownerDocument.createRange(),e=s.ownerDocument.createRange();t.selectNode(u);t.collapse(true);e.selectNode(s);e.collapse(true);var v=t.compareBoundaryPoints(Range.START_TO_END,e);if(v===0){o=true}return v}}}}(function(){var s=document.createElement("div"),t="script"+(new Date).getTime();s.innerHTML="<a name='"+t+"'/>";var e=document.documentElement;e.insertBefore(s,e.firstChild);if(!!document.getElementById(t)){f.find.ID=function(v,w,x){if(typeof w.getElementById!=="undefined"&&!x){var u=w.getElementById(v[1]);return u?u.id===v[1]||typeof u.getAttributeNode!=="undefined"&&u.getAttributeNode("id").nodeValue===v[1]?[u]:undefined:[]}};f.filter.ID=function(w,u){var v=typeof w.getAttributeNode!=="undefined"&&w.getAttributeNode("id");return w.nodeType===1&&v&&v.nodeValue===u}}e.removeChild(s);e=s=null})();(function(){var e=document.createElement("div");e.appendChild(document.createComment(""));if(e.getElementsByTagName("*").length>0){f.find.TAG=function(s,w){var v=w.getElementsByTagName(s[1]);if(s[1]==="*"){var u=[];for(var t=0;v[t];t++){if(v[t].nodeType===1){u.push(v[t])}}v=u}return v}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){f.attrHandle.href=function(s){return s.getAttribute("href",2)}}e=null})();if(document.querySelectorAll){(function(){var e=b,t=document.createElement("div");t.innerHTML="<p class='TEST'></p>";if(t.querySelectorAll&&t.querySelectorAll(".TEST").length===0){return}b=function(x,w,u,v){w=w||document;if(!v&&w.nodeType===9&&!p(w)){try{return a(w.querySelectorAll(x),u)}catch(y){}}return e(x,w,u,v)};for(var s in e){b[s]=e[s]}t=null})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var e=document.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}f.order.splice(1,0,"CLASS");f.find.CLASS=function(s,t,u){if(typeof t.getElementsByClassName!=="undefined"&&!u){return t.getElementsByClassName(s[1])}};e=null})()}function n(s,x,w,B,y,A){var z=s=="previousSibling"&&!A;for(var u=0,t=B.length;u<t;u++){var e=B[u];if(e){if(z&&e.nodeType===1){e.sizcache=w;e.sizset=u}e=e[s];var v=false;while(e){if(e.sizcache===w){v=B[e.sizset];break}if(e.nodeType===1&&!A){e.sizcache=w;e.sizset=u}if(e.nodeName===x){v=e;break}e=e[s]}B[u]=v}}}function r(s,x,w,B,y,A){var z=s=="previousSibling"&&!A;for(var u=0,t=B.length;u<t;u++){var e=B[u];if(e){if(z&&e.nodeType===1){e.sizcache=w;e.sizset=u}e=e[s];var v=false;while(e){if(e.sizcache===w){v=B[e.sizset];break}if(e.nodeType===1){if(!A){e.sizcache=w;e.sizset=u}if(typeof x!=="string"){if(e===x){v=true;break}}else{if(b.filter(x,[e]).length>0){v=e;break}}}e=e[s]}B[u]=v}}}var h=document.compareDocumentPosition?function(s,e){return s.compareDocumentPosition(e)&16}:function(s,e){return s!==e&&(s.contains?s.contains(e):true)};var p=function(e){return e.nodeType===9&&e.documentElement.nodeName!=="HTML"||!!e.ownerDocument&&e.ownerDocument.documentElement.nodeName!=="HTML"};var g=function(e,y){var u=[],v="",w,t=y.nodeType?[y]:y;while((w=f.match.PSEUDO.exec(e))){v+=w[0];e=e.replace(f.match.PSEUDO,"")}e=f.relative[e]?e+"*":e;for(var x=0,s=t.length;x<s;x++){b(e,t[x],u)}return b.filter(v,u)};window.Sizzle=b})();

window.$$ = Sizzle

// Element.prototype.getElementsByClassName=function(c){return $$('.'+c, this)}

if (!document.getElementsByClassName)
{
	Element.prototype.getElementsByClassName = document.getElementsByClassName = function (className, tagName)
	{
		var children = this.getElementsByTagName(tagName || '*'),
			rex = new RegExp("(?:\\s+|^)" + className + "(?:\\s+|$)")
		
		var res = []
		for (var l = 0, i = 0, il = children.length; i < il; i++)
			if (rex.test(children[i].className))
				res[l++] = children[i]
		
		return res
	}
}

$.onready = function (fn) { return this.onready.listeners.push(fn) }
$.onready.done = 0
$.onready.listeners = []
$.onready.run = function (e)
{
	if (this.done++)
		return
	
	if (!e)
		e = {type:'contentready'}
	
	var listeners = this.listeners
	for (var i = 0; i < listeners.length; i++)
		listeners[i].call(document, e)
}
$.onload(function (e) { $.onready.run(e) })
self.addEventListener('DOMContentLoaded', function (e) { $.onready.run(e) }, false)
;(function(){

var R = RegExp, rexCache = {}

Object.add
(
	Element.prototype,
	{
		setClassName: function (cn)
		{
			this.className = cn
			return cn
		},
		
		addClassName: function (cn)
		{
			// this.removeClassName(cn)
			var className = this.className
			if (!className)
				this.className = cn
			else
				this.className = className + ' ' + cn
			return cn
		},
		
		addClassNames: function (cns)
		{
			var className = this.className
			if (!className)
				this.className = cns.join(' ')
			else
				this.className = className + ' ' + cns.join(' ')
			return cns
		},
		
		removeClassName: function (cn)
		{
			var className = this.className
			if (className)
			{
				// the following regexp has to be the exact copy of the regexp from hasClassName()
				// because these two methods have the same regexp cache
				this.className = className.replace(rexCache[cn] || (rexCache[cn] = new R('(?:^| +)(?:' + cn + '(?:$| +))+', 'g')), ' ')
										  .replace(/^\s+|\s+$/g, '') // trim
			}
			return cn
		},
		
		toggleClassName: function (cn, state)
		{
			if (arguments.length < 2)
				state = !this.hasClassName(cn)
			
			this.removeClassName(cn)
			if (state)
				this.addClassName(cn)
		},
		
		hasClassName: function (cn)
		{
			var className = this.className
			if (className == cn)
				return true
			
			// the following regexp has to be the exact copy of the regexp from removeClassName()
			// because these two methods have the same regexp cache
			var rex = rexCache[cn]
			if (rex)
				rex.lastIndex = 0
			else
				rex = rexCache[cn] = new R('(?:^| +)(?:' + cn + '(?:$| +))+', 'g')
			
			return rex.test(className)
		},
		
		empty: function ()
		{
			var node
			while (node = this.firstChild)
				this.removeChild(node)
		},
		
		hide: function () { this.addClassName('hidden') },
		show: function () { this.removeClassName('hidden') },
		
		remove: function ()
		{
			var parent = this.parentNode
			return parent ? parent.removeChild(this) : this
		},
		
		isParent: function (parent, root)
		{
			var node = this
			do
			{
				if (node === parent)
					return true
				if (node === root)
					break
			}
			while ((node = node.parentNode))
			
			return false
		},
		
		offsetPosition: function (root)
		{
			var node = this,
				left = 0, top = 0
			
			if (node == root)
				return {left: left, top: top}
			
			var parent, lastNode
			for (;;)
			{
				left += node.offsetLeft
				top += node.offsetTop
				
				parent = node.offsetParent
				if (parent && parent !== root)
				{
					lastNode = node
					node = parent
				}
				else
				{
					if (lastNode)
					{
						left -= lastNode.scrollLeft
						top -= lastNode.scrollTop
					}
					
					break
				}
			}
			
			return {left: left, top: top}
		}
	}
)

})();
;(function(){

var doc = document, undef, myName = 'NodesShortcut'

function T (text)
{
	return doc.createTextNode(text)
}

function N (tag)
{
	return doc.createElement(tag)
}

function Nc (tag, cn)
{
	var node = doc.createElement(tag)
	node.className = cn
	return node
}

function Nct (tag, cn, text)
{
	var node = doc.createElement(tag)
	node.className = cn
	node.appendChild(doc.createTextNode(text))
	return node
}


function E (tag, cn, props)
{
	var node = doc.createElement(tag)
	if (cn !== undef) node.className = cn
	if (props)
		for (var i in props)
			node.setAttribute(i, props[i])
	return node
}

var Me = self[myName] = {}
	funcs = Me.funcs = {T: T, N: N, Nc: Nc, Nct: Nct, E: E}

var pairs = []
for (var k in funcs)
	pairs.push(k + '=' + myName + '.funcs.' + k)

Me.code = 'var ' + pairs.join(',')
Me.include = function () { return this.code }


})();

;(function(){

var myName = 'EventDriven',
	Me = self[myName] = function () {},
	handlersProp = '__' + myName + 'Handlers',
	doc = document

Me.prototype =
{
	addEventListener: function (type, listener, capture)
	{
		var handlers, harr
		if (handlers = this[handlersProp])
		{
			if (harr = handlers[type])
				harr.indexOf(listener) < 0 ? harr.push(listener) : 1
			else
				handlers[type] = [listener]
		}
		else
			(this[handlersProp] = {})[type] = [listener]
	},
	
	removeEventListener: function (type, listener, capture)
	{
		var handlers, harr, i
		if (handlers = this[handlersProp])
			if ((harr = handlers[type]))
			{
				if ((i = harr.indexOf(listener)) >= 0)
				{
					for (len = harr.length; i < len; i++)
						harr[i] = harr[i + 1]
					harr.length--
				}
			}
	},
	
	dispatchEvent: function (e)
	{
		e.__dispatched = true
		var handlers, harr, len
		if ((handlers = this[handlersProp]))
			if ((harr = handlers[e.type]))
				if ((len = harr.length))
				{
					for (var i = 0; i < len; i++)
						harr[i].call(this, e)
					return !e.defaultPrevented
				}
		
		return true
	},
	
	dispatchEventData: function (type, data)
	{
		var e = new Event()
		e.type = type
		e.data = data
		return this.dispatchEvent(e)
	}
}

function Event () {}

Event.prototype =
{
	bubbles: true,
	cancelable: true,
	
	preventDefault: function ()
	{
		if (this.__dispatched && this.cancelable)
			this.defaultPrevented = true
	},
	
	stopPropagation: function ()
	{
		this.propagationStopped = true
	},
	
	initEvent: function (type, bubbles, cancelable)
	{
		this.type = type
		this.bubbles = bubbles
		this.cancelable = cancelable
	}
}

Me.Event = Event

})();

;(function () {

var myName = 'GlobalTimer', Me =
{
	fps: 60,
	total: 0,
	id: 0,
	timers: {},
	timer: null,
	
	tick: function (d)
	{
		var timer, timers = this.timers
		for (var id in timers)
			if ((timer = timers[id]))
				timer(d)
	},
	
	add: function (callback)
	{
		// if was no timers
		if (this.total++ <= 0)
		{
			if (this.timer !== null)
				throw new Error(myName + '.timer had been broken')
			var me = this
			this.timer = setInterval(function (d) { me.tick(d) }, 1000 / this.fps)
		}
		
		this.timers[++this.id] = callback
		return this.id
	},
	
	remove: function (id)
	{
		if (id in this.timers)
		{
			var callback = this.timers[id]
			delete this.timers[id]
			
			// if have deleted last timer
			if (--this.total <= 0)
			{
				clearInterval(this.timer)
				this.timer = null
			}
			
			return callback
		}
	},
	
	clear: function (d)
	{
		var timers = this.timers
		for (var id in timers)
			this.remove(id)
	}
}

self[myName] = Me

})();

;(function(){

function Kinematics () {}
Kinematics.className = 'Kinematics'
self[Kinematics.className] = Kinematics

var fps = Kinematics.fps = GlobalTimer.fps

function stub () {}

function Space ()
{
	this.timers = {}
	this.ticks = 0
	this.freeze = 0
	this.points = []
	this.forces = []
}

Space.prototype =
{
	minPulse: 1 / (fps * fps *10),
	maxFreeze: fps, // wait one second before freeze
	
	ontick: stub,
	ontimeout: stub,
	onfreeze: stub,
	
	run: function (timeout)
	{
		var me = this
		clearTimeout(this.timers.timeout)
		if (timeout)
			this.timers.timeout = setTimeout(function (d) { me.timeout(d) }, timeout)
		
		if (this.running)
			return
		this.running = true
		
		this.freeze = 0
		
		this.timers.tick = GlobalTimer.add(function (d) { me.tick(d) })
	},
	
	timeout: function (d)
	{
		this.ontimeout()
		this.stop()
	},
	
	stop: function ()
	{
		if (!this.running)
			return
		this.running = false
		
		clearTimeout(this.timers.timeout)
		GlobalTimer.remove(this.timers.tick)
	},
	
	tick: function (d)
	{
		this.ticks++
		
		var forces = this.forces, points = this.points
		for (var i = 0, il = forces.length; i < il; i++)
		{
			var force = forces[i]
			for (var j = 0, jl = points.length; j < jl; j++)
				force.apply(points[j])
		}
		
		this.ontick()
		
		var pulse = 0
		for (var i = 0, il = points.length; i < il; i++)
		{
			var p = points[i], v = p.v
			p.x += v.x
			p.y += v.y
		}
		
		for (var i = 0, il = points.length; i < il; i++)
		{
			var v = points[i].v
			pulse += v.x * v.x + v.y * v.y
		}
		
		if (!pulse || pulse < this.minPulse)
		{
			if (++this.freeze == this.maxFreeze)
			{
				this.freeze = 0
				if (this.onfreeze() !== false)
					this.stop()
			}
		}
		else
			this.freeze = 0
		
		this.pulse = pulse
	},
	
	add: function (object)
	{
		if (object instanceof Force)
			this.forces.push(object)
		else if (object instanceof Point)
			this.points.push(object)
		else
			throw new Error('unknown object added ' + object)
		
		return object
	}
}

Space.className = 'Space'
Kinematics[Space.className] = Space


function Point (x, y, vx, vy, m)
{
	this.x = x || 0
	this.y = y || 0
	this.m = m || 1
	this.v = new Vector(vx ? vx / fps : 0, vy ? vy / fps : 0)
}

Point.prototype =
{
	
}

Point.className = 'Point'
Kinematics[Point.className] = Point


function Force () {}

Force.prototype =
{
	apply: function () {}
}

Force.className = 'Force'
Kinematics[Force.className] = Force



function Friction (mu)
{
	this.mu = mu / fps
}

Friction.prototype = new Force()
Friction.prototype.apply = function (point)
{
	point.v.addC(-this.mu)
}

Friction.className = 'Friction'
Kinematics[Friction.className] = Friction



function Wave (step, soft, min)
{
	this.setup(step, soft, min)
}

Wave.prototype = new Force()
Wave.prototype.setup = function (step, soft, min, max)
{
	this.step = step
	this.soft = soft || 10
	this.min = min / fps || 0
	this.max = max / fps || 500
}
Wave.prototype.apply = function (point)
{
	var x = Math.round(point.x), step = this.step,
		pos = x % step,
		shift = x < 0 ? step + pos : pos,
		dir = shift > step / 2 ? shift - step : shift,
		sign = dir < 0 ? 1 : -1,
		v = Math.sqrt(Math.abs(dir)) / this.soft
	
	if (v < this.min)
		v = this.min
	else if (v > this.max)
		v = this.max
	
	if (dir)
		point.v.addX(sign * v)
}

Wave.className = 'Wave'
Kinematics[Wave.className] = Wave



function Vector (x, y)
{
	this.x = x
	this.y = y
	this.h = -1
}

Vector.prototype =
{
	set: function (x, y)
	{
		this.x = x
		this.y = y
		this.h = -1
	},
	
	addX: function (x)
	{
		this.x += x
		this.h = -1
	},
	
	add: function (x, y)
	{
		this.x += x
		this.y += y
		this.h = -1
	},
	
	addC: function (c)
	{
		var x = this.x, y = this.y
		
		var h = this.h
		if (h === -1)
			h = this.h = Math.sqrt(x * x + y * y)
		
		if (h === 0)
			return
		
		var cos = x / h,
			sin = y / h
		
		h += c
		
		if (h > 0)
		{
			this.x = h * cos
			this.y = h * sin
			this.h = h
		}
		else
		{
			this.x = 0
			this.y = 0
			this.h = 0
		}
	}
}

Vector.className = 'Vector'
self[Vector.className] = Vector


})();
;(function(){

var myName = 'Moveable'

function Me () {}

function preventDefault (e){ e.preventDefault() }
var dropClick = false
function onclick (e)
{
	if (dropClick)
	{
		e.preventDefault()
		dropClick = false
	}
}
Me.dropClick = function () { dropClick = true }

var clickListener = false
Me.bindClickListened = function ()
{
	if (clickListener)
		return
	
	document.addEventListener('click', onclick, true)
	clickListener = true
}

Me.prototype =
{
	bind: function (node)
	{
		this.node = node
		
		var me = this
		this.mousedown = function (e) { me.ondown(e) }
		this.mousemove = function (e) { me.onmove(e) }
		this.mousemove2 = function (e) { me.onmove2(e) }
		this.mouseup = function (e) { me.onup(e) }
		this.mouseup2 = function (e) { me.onup2(e) }
		
		node.addEventListener('mousedown', this.mousedown, false)
		node.addEventListener('selectstart', preventDefault, false)
		
		Me.bindClickListened()
		
		return this
	},
	
	ondown: function (e)
	{
		if (this.disabled)
			return
		
		if (this.dispatchEventData('moveabout', {event: e, mousedownEvent: this.mousedownEvent}))
		{
			this.startX = e.clientX
			this.startY = e.clientY
			this.movements = []
			this.mousedownEvent = e
			
			e.preventDefault()
			
			document.addEventListener('mousemove', this.mousemove, true)
			document.addEventListener('mouseup', this.mouseup, true)
		}
	},
	
	onmove: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		this.movements.push({dx: dx, dy: dy})
		
		if (dx * dx > 9 || dy * dy > 9)
		{
			if (this.dispatchEventData('movestart', {event: e, mousedownEvent: this.mousedownEvent}))
			{
				Me.dropClick()
				
				if (this.softStart)
				{
					this.startX = e.clientX
					this.startY = e.clientY
				}
				
				document.removeEventListener('mousemove', this.mousemove, true)
				document.removeEventListener('mouseup', this.mouseup, true)
				
				document.addEventListener('mousemove', this.mousemove2, true)
				document.addEventListener('mouseup', this.mouseup2, true)
				
				this.onmove2(e)
			}
		}
		else
			this.dispatchEventData('movestarting', {event: e, mousedownEvent: this.mousedownEvent})
	},
	
	onup: function (e)
	{
		document.removeEventListener('mousemove', this.mousemove, true)
		document.removeEventListener('mouseup', this.mouseup, true)
		this.mousedownEvent = null
	},
	
	onmove2: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		this.movements.push({dx: dx, dy: dy})
		
		e.preventDefault()
		e.stopPropagation()
		
		if (this.lastDX != dx || this.lastDY != dy)
		{
			this.lastDX = dx
			this.lastDY = dy
			this.dispatchEventData('move', {event: e, dx: dx, dy: dy})
		}
	},
	
	onup2: function (e)
	{
		var dx = e.clientX - this.startX,
			dy = e.clientY - this.startY
		
		if (this.dispatchEventData('moveend', {event: e, dx: dx, dy: dy, movements: this.movements}))
		{
			e.preventDefault()
			e.stopPropagation()
			
			document.removeEventListener('mousemove', this.mousemove2, true)
			document.removeEventListener('mouseup', this.mouseup2, true)
		}
		
		this.mousedownEvent = null
	}
}

Me.mixIn(EventDriven)

self[myName] = Me
Me.className = myName

})();
;(function(){

var myName = 'InfiniteScroller'

function Me ()
{
	this.nodes = {}
}

Me.prototype =
{
	power: 1.5,
	spaceTimeout: 30000,
	maxInertia: 500,
	onscroll: function () {},
	
	bind: function (root, width)
	{
		this.nodes.root = root
		this.globalX = root.scrollLeft
		
		var clientWidth = root.clientWidth
		this.setWidth(width || this.guessWidth())
		
		var moveable = this.moveable = new Moveable().bind(root)
		moveable.softStart = true
		
		var me = this
		moveable.addEventListener('moveabout', function (e) { me.onmoveabout(e) }, false)
		moveable.addEventListener('movestart', function (e) { me.onmovestart(e) }, false)
		moveable.addEventListener('move', function (e) { me.onmoving(e) }, false)
		moveable.addEventListener('moveend', function (e) { me.onmoveend(e) }, false)
		
		this.setX = function (x)
		{
			if (me.globalX == x)
				return
			me.globalX = x
			
			var w = me.width,
				real
			if (w == 0)
				real = 0
			else
				real = x < 0 ? w + x % w : x % w
			root.scrollLeft = Math.round(real)
			this.onscroll(x, real)
		}
		
		
		var space = this.space = new Kinematics.Space()
		var point = this.point = new Kinematics.Point(0, 0, 0, 0)
		space.add(point)
		
		space.ontick = function () { me.spaceTick() }
		
		return this
	},
	
	guessWidth: function ()
	{
		var root = this.nodes.root
		return root.scrollWidth - root.clientWidth
	},
	
	setWidth: function (width)
	{
		this.width = width
	},
	
	setMovable: function (v)
	{
		this.moveable.disabled = !v
	},
	
	reset: function ()
	{
		this.space.stop()
		this.setX(0)
		this.point.x = this.globalX
		this.setVelocity(0, 0)
	},
	
	spaceTick: function ()
	{
		this.setX(this.point.x)
	},
	
	onmovestart: function (e)
	{
		this.space.stop()
		this.startX = this.globalX
		this.nodes.root.addClassName('grabbing')
	},
	
	onmoveabout: function ()
	{
		if (this.space.running)
		{
			Moveable.dropClick()
			this.space.stop()
		}
	},
	
	onmoving: function (e)
	{
		this.setX(this.startX - e.data.dx)
	},
	
	onmoveend: function (e)
	{
		this.nodes.root.removeClassName('grabbing')
		
		var ms = e.data.movements.reverse()
		if (!ms[3])
			return
		
		var root = this.nodes.root,
			// approximating last movements
			vx = ((ms[1].dx - ms[0].dx) + (ms[2].dx - ms[1].dx) + (ms[3].dx - ms[2].dx)) / 3// + (ms[4].dx - ms[3].dx) + (ms[5].dx - ms[4].dx)) / 5
		
		if (Math.abs(vx) > this.maxInertia)
			vx = (vx < 0 ? -1 : 1) * this.maxInertia
		
		this.point.x = this.globalX
		this.setVelocity(vx ? vx * this.power : 0, 0)
		this.run()
	},
	
	addVelocity: function (x, y)
	{
		this.point.v.add(x, y)
	},
	
	setVelocity: function (x, y)
	{
		this.point.v.set(x, y)
	},
	
	run: function (timeout)
	{
		this.space.run(timeout === undefined ? this.spaceTimeout : timeout) // set a reasonable timeout
	}
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Gridder'

function Me (boxes, x, y)
{
	this.boxes = []
	this.gridH = {}
	this.gridA = []
	this.constructor = Me
	
	if (boxes)
		this.setBoxes(boxes)
	
	if (x && y)
		this.setStep(x, y)
}

Me.prototype =
{
	stepX: 500, stepY: 500,
	maxSteps: 5000,
	
	reflow: function ()
	{
		var boxes = this.boxes, gridH = this.gridH = {}, gridA = this.gridA = [],
			sx = this.stepX, sy = this.stepY,
			stepsLeft = this.maxSteps
		
		var ceil = Math.ceil
		
		for (var i = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i]
			
			// mark box with an integer ID
			// simplifying future operations of search
			box.boxID = i
			
			// x and width
			var x1, x2, x = box.x, w = box.w
			x1 = x < 0 ? -ceil(-x / sx) : x / sx >> 0
			if (w <= 0)
				x2 = x1
			else
			{
				x += w
				x2 = x > 0 ? ceil(x / sx) - 1 : (x / sx >> 0) - 1
			}
			
			// y and height
			var y1, y2, y = box.y, h = box.h
			y1 = y < 0 ? -ceil(-y / sy) : y / sy >> 0
			if (h <= 0)
				y2 = y1
			else
			{
				y += h
				y2 = y > 0 ? ceil(y / sy) - 1 : (y / sy >> 0) - 1
			}
			
			for (var x = x1; x <= x2; x++)
			for (var y = y1; y <= y2; y++)
			{
				if (0 == stepsLeft--)
					throw new Me.Error('too many steps (' + this.maxSteps + ')')
				
				// check diapason of the values
				if (x >> 15 || y >> 15)
				{
					// unsafe, so using slow string key on gridH
					var key = x + ':' + y
					
					var cell = gridH[key]
					if (cell)
						cell.push(box)
					else
						gridH[key] = [box]
					
				}
				else
				{
					// safe, so using fast integer key on gridA
					var key = (x << 15) + y
					
					var cell = gridA[key]
					if (cell)
						cell.push(box)
					else
						gridA[key] = [box]
				}
			}
		}
	},
	
	// as far as JavaScript has no macros system or semi-reliable function inlining
	// you can see a heavy copy-paste here, it's for performance purpose only
	getCells: function (x, y, w, h)
	{
		var gridH = this.gridH, gridA = this.gridA,
			sx = this.stepX, sy = this.stepY,
			stepsLeft = this.maxSteps
		
		var ceil = Math.ceil
		
		// x and width
		var x1 = x < 0 ? -ceil(-x / sx) : x / sx >> 0
		if (w <= 0)
			var x2 = x1
		else
		{
			x += w
			var x2 = x > 0 ? ceil(x / sx) - 1 : (x / sx >> 0) - 1
		}
			
		// y and height
		var y1 = y < 0 ? -ceil(-y / sy) : y / sy >> 0
		if (h <= 0)
			var y2 = y1
		else
		{
			y += h
			var y2 = y > 0 ? ceil(y / sy) - 1 : (y / sy >> 0) - 1
		}
		
		var cells = []
		for (var x = x1; x <= x2; x++)
		for (var y = y1; y <= y2; y++)
		{
			if (0 == stepsLeft--)
				throw new Me.Error('too many steps (' + this.maxSteps + ')')
			
			// check diapason of the values
			if (x >> 15 || y >> 15)
			{
				// unsafe, so using slow string key on gridH
				var key = x + ':' + y
				
				var cell = gridH[key]
				if (cell)
					cells.push(cell)
			}
			else
			{
				// safe, so using fast integer key on gridA
				var key = (x << 15) + y
				
				var cell = gridA[key]
				if (cell)
					cells.push(cell)
			}
		}
		
		return cells
	},
	
	getBoxes: function (x, y, w, h)
	{
		var cells = this.getCells(x, y, w, h),
			seen = [], boxes = [], k = 0
		
		for (var i = 0, il = cells.length; i < il; i++)
		{
			var cell = cells[i]
			for (var j = 0; j < cell.length; j++)
			{
				var box = cell[j], id = box.boxID
				if (!seen[id])
				{
					seen[id] = true
					boxes[k++] = box
				}
			}
		}
		
		return boxes
	},
	
	getBoxesPrecise: function (x, y, w, h)
	{
		var boxes = this.getBoxes(x, y, w, h),
			res = []
		
		var ax1 = x, ax2 = ax1 + w, ay1 = y, ay2 = ay1 + h
		for (var i = 0, j = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i]
			
			var bx1 = box.x, bx2 = bx1 + box.w, by1 = box.y, by2 = by1 + box.h
			
			// checking x
			if (ax2 <= bx1 || bx2 <= ax1)
				continue
			
			// checking y
			if (ay2 <= by1 || by2 <= ay1)
				continue
			
			res[j++] = box
		}
		
		return res
	},
	
	setStep: function (x, y)
	{
		this.stepX = x
		this.stepY = y
		this.reflow()
	},
	
	setBoxes: function (boxes)
	{
		this.boxes = boxes
		this.reflow()
	},
	
	getCell: function (x, y)
	{
		return x >> 15 || y >> 15 ? this.gridH[x + ':' + y] : this.gridA[(x << 15) + y]
	}
}

Me.Error = function (m) { this.name = myName + '.Error'; this.message = m }
Me.Error.prototype = new Error()

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'VisibilityFrame'

function Me ()
{
	this.x = 0
	this.y = 0
	this.gridder = new Gridder()
	this.boxes = []
	this.visible = {}
	this.constructor = Me
}

Me.prototype =
{
	onmove: function (show, hide, visible) {},
	
	setBoxes: function (boxes)
	{
		this.boxes = boxes
		this.visible = {}
		
		this.gridder.setBoxes(boxes)
		this.update()
	},
	
	setFrame: function (w, h, x, y)
	{
		this.width = w
		this.height = h
		
		if (x && y)
			this.setStep(x, y)
	},
	
	setStep: function (x, y)
	{
		this.gridder.setStep(x, y)
	},
	
	// much faster version
	moveTo: function (x, y)
	{
		this.x = x
		this.y = y
		
		var last = this.visible, current = {}, show = [], hide = []
		
		var boxes = this.gridder.getBoxesPrecise(x, y, this.width, this.height)
		for (var i = 0, il = boxes.length; i < il; i++)
		{
			var box = boxes[i],
				id = box.boxID
			
			if (id in last)
				delete last[id]
			else
				show.push(box)
			
			current[id] = box
		}
		
		for (var k in last)
			hide.push(last[k])
		
		this.visible = current
		
		this.onmove(show, hide, boxes)
	},
	
	update: function ()
	{
		this.moveTo(this.x, this.y)
	}
	
	// // slow version
	// moveTo: function (x, y)
	// {
	// 	var boxes = this.gridder.getBoxesPrecise(x, y, this.width, this.height)
	// 	
	// 	var visible = this.visible
	// 	this.visible = boxes
	// 	
	// 	this.onmove(boxes, visible, boxes)
	// }
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Boxer'

var Me =
{
	nodesToBoxes: function (nodes, root, width, height)
	{
		var boxes = []
		
		var custom = width !== undefined && height !== undefined
		
		var lastParent = root, position = {left: 0, top: 0}
		for (var i = 0, il = nodes.length; i < il; i++)
		{
			var node = nodes[i],
				parent = node.offsetParent
			
			if (parent != lastParent)
			{
				lastParent = parent
				position = parent.offsetPosition(root)
			}
			
			var box = boxes[i] =
			{
				x: node.offsetLeft + position.left,
				y: node.offsetTop + position.top,
				node: node
			}
			
			if (custom)
			{
				box.w = width
				box.h = height
			}
			else
			{
				box.w = node.offsetWidth
				box.h = node.offsetHeight
			}
		}
		
		return boxes
	},
	
	sameNodesToBoxes: function (nodes, root)
	{
		var first = nodes[0]
		if (!first)
			return []
		
		return this.nodesToBoxes(nodes, root, first.offsetWidth, first.offsetHeight)
	}
}

// Me.mixIn(EventDriven)
Me.className = myName
self[myName] = Me

})();
;(function(){

var Me =
{
	guessOS: function (ua)
	{
		if (/Windows/.test(ua))
			return ['win']
		
		if (/Macintosh|Mac OS/.test(ua))
			return ['mac']
		
		if (/Linux/.test(ua))
			return ['linux']
		
		return []
	},
	
	guessBrowser: function (ua)
	{
		function classes (n, a, b, c)
		{
			return [n, n + '-' + a, n + '-' + a + '-' + b, n + '-' + a + '-' + b + '-' + c]
		}
		
		var m = /Opera\/\d+.+Version\/(\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Opera\/(\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Opera (\d+)\.(\d)(\d)/.exec(ua)
		if (m)
			return classes('opera', m[1], m[2], m[3])
		
		var m = /Firefox\/(\d+)\.(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('firefox', m[1], m[2], m[3])
		
		var m = /Firefox\/(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('firefox', m[1], m[2], 0)
		
		var m = /MSIE (\d+)\./.exec(ua)
		if (m)
			return ['msie', 'msie-' + m[1]]
		
		var m = /Version\/(\d+)\.(\d+)\.(\d+) Safari\/\d+/.exec(ua)
		if (m)
			return classes('safari', m[1], m[2], m[3])
		
		var m = /Version\/(\d+)\.(\d+) Safari\/\d+/.exec(ua)
		if (m)
			return classes('safari', m[1], m[2], 0)
		
		var m = /Chrome\/(\d+)\.(\d+)\.(\d+)/.exec(ua)
		if (m)
			return classes('chrome', m[1], m[2], m[3])
		
		return []
	},
	
	getClassNames: function (ua)
	{
		return this.guessOS(ua).concat(this.guessBrowser(ua))
	},
	
	setupDocumentElementClassNames: function (ua)
	{
		document.documentElement.addClassNames(this.getClassNames(ua || navigator.userAgent))
	}
}

Me.className = 'UserAgent'
self[Me.className] = Me

})();



;(function(){

var myName = 'Statistics'

var Me =
{
	magazinePromoViewed: function (promo)
	{
		this.track('magazine-promo-viewed', promo && promo.name)
	},
	
	cocktailsFilterSelected: function (name)
	{
		this.track('cocktails-filter-selected', name)
	},
	
	cocktailViewRecipe: function (cocktail)
	{
		this.track('cocktail-view-recipe', cocktail && cocktail.name)
	},
	
	cocktailAddedToCalculator: function (cocktail)
	{
		this.track('cocktail-added-to-calculator', cocktail && cocktail.name)
	},
	
	toolPopupOpened: function (tool)
	{
		this.track('tool-popup', tool && tool.name)
	},
	
	ingredientPopupOpened: function (ingredient)
	{
		this.track('ingredient-popup', ingredient && ingredient.name)
	},
	
	ingredientTypedIn: function (ingredient)
	{
		this.track('ingredient-typed-in', ingredient && ingredient.name)
	},
	
	ingredientSelected: function (ingredient)
	{
		this.track('ingredient-selected', ingredient && ingredient.name)
	},
	
	combinatorQueryRaw: function (query)
	{
		this.track('combinator-query-raw', query)
	},
	
	combinatorQueryViewed: function (query)
	{
		this.track('combinator-query', query)
	},
	
	track: function (action, label, value)
	{
		setTimeout(function () { Tracker.track('UserAction', action, label, value) }, 500)
	}
}

Me.className = myName
self[myName] = Me

})();
;(function(){

var myName = 'Throttler'

function Me (callback, delay, timeout, invocant)
{
	this.callback = callback
	this.delay = delay
	this.timeout = timeout
	this.invocant = invocant || self
	this.delayTimer = 0
	this.timeoutTimer = 0
	
	var me = this
	this.timeoutCallback = function () { me.fire() }
	this.timerCallback = function () { me.fire() }
}

Me.prototype =
{
	call: function ()
	{
		this.args = arguments
		
		clearTimeout(this.delayTimer)
		this.delayTimer = setTimeout(this.timerCallback, this.delay)
		
		if (!this.timeoutTimer)
			this.timeoutTimer = setTimeout(this.timeoutCallback, this.timeout)
	},
	
	fire: function ()
	{
		var delayTimer = this.delayTimer
		if (delayTimer)
		{
			clearTimeout(delayTimer)
			this.delayTimer = 0
		}
		
		var timeoutTimer = this.timeoutTimer
		if (timeoutTimer)
		{
			clearTimeout(timeoutTimer)
			this.timeoutTimer = 0
		}
		
		this.callback.apply(this.invocant, this.args)
	}
}

Me.className = myName
self[myName] = Me

})();

;(function(){

function Me ()
{
	this.nodes = {}
	this.boxes = []
	this.conf =
	{
		// precalculated velocity that must be applied to go to the next page
		pageVelocity: 20,
		
		// nodes on one page, list becomes active or inactive (single) relying on this
		pageLength: 1,
		
		// just a friction to be set in the scroller space
		friction: 60,
		
		// how much soften will wave be
		soft: 10,
		
		// steps of the gridder, defaults are nive enough
		stepX: 500,
		stepY: 500,
		
		// the time to wait the next onscroll event before take any actions
		throttleSoft: 100,
		throttleHard: 500
	}
	this.constructor = Me
}

Me.className = 'LazyList'

Me.prototype =
{
	// a callback for nodes must be loaded
	load: function () {},
	
	configure: function (conf)
	{
		Object.extend(this.conf, conf)
		
		conf = this.conf
		if (conf.min === undefined)
			conf.min = conf.friction * 2
	},
	
	bind: function (nodes, cocktails)
	{
		this.nodes = nodes
		
		this.bindScroller()
		this.navigate()
		
		return this
	},
	
	bindScroller: function ()
	{
		var nodes = this.nodes,
			surface = nodes.surface, viewport = nodes.viewport
		
		var frame = this.frame = new VisibilityFrame()
		frame.setStep(this.conf.stepX, this.conf.stepY)
		
		var me = this
		frame.onmove = function (show, hide)
		{
			var load = []
			for (var i = 0; i < show.length; i++)
			{
				var box = show[i]
				if (!box.loaded)
				{
					load.push(box.node)
					box.loaded = true
				}
			}
			
			me.load(load)
		}
		
		var scroller = this.scroller = new InfiniteScroller()
		scroller.bind(viewport)
		
		var space = scroller.space
		space.add(new Kinematics.Friction(this.conf.friction))
		this.wave = space.add(new Kinematics.Wave(0, 0, 0))
	},
	
	setNodes: function (nodes, realCount)
	{
		var n = this.nodes, root = n.root, surface = n.surface, viewport = n.viewport,
			conf = this.conf
		
		var boxes = this.boxes = Boxer.sameNodesToBoxes(nodes, viewport)
		
		var frame = this.frame,
			frameWidth = viewport.offsetWidth
		
		var t = new Throttler(function (x, realX) { frame.moveTo(realX - frameWidth, 0) }, conf.throttleSoft, conf.throttleHard)
		this.scroller.onscroll = function (x, realX) { t.call(x, realX) }
		
		frame.setFrame(frameWidth * 3, viewport.offsetHeight)
		frame.setBoxes(boxes)
		frame.moveTo(0, 0)
		
		
		root.show()
		
		var scroller = this.scroller
		scroller.reset()
		
		if (realCount >= conf.pageLength)
		{
			root.removeClassName('single')
			root.removeClassName('empty')
			
			var last = boxes[realCount - 1]
			this.scroller.setWidth(last.x + last.w)
			this.wave.setup(last.w, conf.soft, conf.min)
			scroller.setMovable(true)
		}
		else if (realCount == 0)
		{
			root.removeClassName('single')
			root.addClassName('empty')
			scroller.setMovable(false)
		}
		else
		{
			root.addClassName('single')
			root.removeClassName('empty')
			scroller.setMovable(false)
		}
	},
	
	navigate: function ()
	{
		var nodes = this.nodes
		
		var me = this
		nodes.prev.addEventListener('click', function (e) { me.goPrev() }, false)
		nodes.next.addEventListener('click', function (e) { me.goNext() }, false)
	},
	
	goPrev: function ()
	{
		this.scroller.setVelocity(-this.conf.pageVelocity, 0)
		this.scroller.run()
	},
	
	goNext: function ()
	{
		this.scroller.setVelocity(this.conf.pageVelocity, 0)
		this.scroller.run()
	},
	
	jumpToNode: function (node)
	{
		var boxes = this.boxes
		SEARCH:
		{
			for (var i = 0, il = boxes.length; i < il; i++)
			{
				var box = boxes[i]
				if (box.node == node)
					break SEARCH
			}
			return
		}
		
		var box = boxes[i - i % this.conf.pageLength]
		if (box)
			this.scroller.setX(box.x)
	}
}

self[Me.className] = Me

})();
;(function(){

function Me ()
{
	this.list = new LazyList()
	this.nodes = {}
	this.conf = {pageLength: 1}
	this.previewsCache = {}
	this.constructor = Me
	this.data = {cocktails:[]}
}

Me.className = 'CocktailList'

Me.prototype =
{
	configure: function (conf)
	{
		this.conf = conf
		this.list.configure(conf)
	},
	
	bind: function (nodes)
	{
		this.nodes = nodes
		
		var list = this.list
		list.bind(nodes)
		list.load = function (nodes)
		{
			for (var i = 0, il = nodes.length; i < il; i++)
			{
				var node = nodes[i],
					image = node.img
				
				image.src = image.lazySrc
				node.removeClassName('lazy')
			}
		}
		
		return this
	},
	
	setCocktails: function (cocktails)
	{
		this.data.cocktails = cocktails
		this.render()
	},
	
	render: function ()
	{
		
		var nodes = this.nodes, root = nodes.root, surface = nodes.surface, viewport = nodes.viewport,
			cocktails = this.data.cocktails
		
		surface.empty()
		
		var nodes = []
		
		for (var i = 0, il = cocktails.length; i < il; i++)
		{
			var preview = cocktails[i].getPreviewNode(true)
			surface.appendChild(preview)
			nodes.push(preview)
		}
		
		var page = this.conf.pageLength
		if (cocktails.length >= page)
		{
			for (var j = 0; j < page; j++)
			{
				var preview = cocktails[j].getPreviewNode()
				surface.appendChild(preview)
			}
		}
		
		this.list.setNodes(nodes, cocktails.length)
	}
}

self[Me.className] = Me

})();
;(function(){

var myName = 'RoundedCorners'

function Me () {}

Me.round = function (node)
{
	node.appendChild(this.corners.cloneNode(true))
}

Me.init = function (node)
{
	var corners = this.corners = document.createElement('b')
	corners.className = 'rounding-corners'
	
	var classes = ['lt', 'rt', 'rb', 'lb']
	for (var i = 0, il = classes.length; i < il; i++)
	{
		var corner = document.createElement('b')
		corner.className = classes[i]
		corners.appendChild(corner)
	}
}

Me.className = myName
self[myName] = Me

Me.init()

})();

$.onready(function () { setTimeout(function () { GoogleAnalytics.trackPageview() }, 250) })

;(function(){

var myName = 'Theme'
var Me = self[myName] =
{
	initialize: function (db)
	{
		this.db = db
	},
	
	bind: function ()
	{
		var db = this.db
		
		for (var k in db)
		{
			var item = db[k]
			if (!item.href)
				continue
			
			var node = $(k)
			if (node)
			{
				node.href = item.href
			}
		}
	}
}

})();

$.onready(function () { Theme.bind() })

$.onready(function ()
{
	var year = $$('#copyright .year')[0]
	if (year)
		year.firstChild.nodeValue = new Date().getFullYear()
})


String.prototype.htmlName = function () { return this.replace(/[^\w\-\.]/g, "_").toLowerCase() }

require.names =
{
	'Good': '/js/entities/Good.js'
}